package com.zbc.manager;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.ImageInfo;
import com.zbc.config.MinioConfig;
import com.zbc.config.TencentCosClient;
import com.zbc.domain.file.UploadPictureResult;
import com.zbc.enums.ErrorCode;
import com.zbc.exception.BusinessException;
import io.minio.MinioClient;
import io.minio.ObjectWriteResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Set;
import java.util.Date;

/**
 * 符合业务的文件上传类
 * @author fangyu
 * @version v1.0.0
 * @since 2025/9/2 15:20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileManager {
    private final TencentCosClient tencentCosClient;
    private final CosManager cosManager;
    private final MinioConfig minioConfig;
    private final MinioManager minioManager;

    /**
     * 文件上传(腾讯云)
     *
     * @param multipartFile    本地文件
     * @param uploadPathPrefix 上传路径前缀
     * @return 封装图片基本信息的对象
     */
    public UploadPictureResult uploadPicture4Tencent(MultipartFile multipartFile, String uploadPathPrefix) {
        // 1. 校验图片(封装为方法)
        validPicture(multipartFile);
        // 2. 拼接文件名称
        String date = DateUtil.formatDate(new Date());
        String uuid = RandomUtil.randomString(10);
        String suffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        String fileName = String.format("%s_%s.%s", date, uuid, suffix);
        // 3. 划分文件夹
        String uploadPath = String.format("/%s/%s", uploadPathPrefix, fileName);
        // 4. 上传图片到 COS
        File file = null;
        try {
            // 1. 创建临时文件
            file = File.createTempFile(uploadPath, null);
            multipartFile.transferTo(file);
            // 2. 上传图片到 COS
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadPath, file);
            // 3. 使用数据万象处理图片
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();
            int width = imageInfo.getWidth();
            int height = imageInfo.getHeight();
            // 计算宽高比
            double scale = NumberUtil.round(width * 1.0 / height, 2).doubleValue();
            // 4. 封装图片信息
            UploadPictureResult result = new UploadPictureResult();
            result.setUrl(tencentCosClient.getHost() + "/" + uploadPath);
            result.setPicName(FileUtil.mainName(multipartFile.getOriginalFilename()));
            result.setPicSize(FileUtil.size(file));
            result.setPicWidth(width);
            result.setPicHeight(height);
            result.setPicScale(scale);
            result.setPicFormat(imageInfo.getFormat());
            return result;
        } catch (Exception e) {
            log.error("file upload fail", e);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "上传失败");
        } finally {
            // 5. 删除临时文件
            deleteTempFile(file);
        }
    }

    public UploadPictureResult uploadPicture4Minio(MultipartFile multipartFile, String uploadPathPrefix) {
        // 1. 校验图片(封装为方法)
        validPicture(multipartFile);
        // 2. 拼接文件名称
        String date = DateUtil.formatDate(new Date());
        String uuid = RandomUtil.randomString(10);
        String suffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        String fileName = String.format("%s_%s.%s", date, uuid, suffix);
        // 3. 划分文件夹
        String uploadPath = String.format("/%s/%s", uploadPathPrefix, fileName);
        // 4. 上传图片到 minio
        File file = null;
        try {
            file = File.createTempFile(uploadPath, null);
            multipartFile.transferTo(file);

            // 替换为MinIO上传
            ObjectWriteResponse response = minioManager.putObject(
                    minioConfig.getBucketName(),
                    uploadPath,
                    file
            );

            // 本地解析图片信息
            BufferedImage image = ImageIO.read(file);
            int width = image.getWidth();
            int height = image.getHeight();
            double scale = NumberUtil.round(width * 1.0 / height, 2).doubleValue();

            UploadPictureResult result = new UploadPictureResult();
            // 构建MinIO访问地址
            result.setUrl(String.format("%s/%s/%s",
                    minioConfig.getEndpoint(),
                    minioConfig.getBucketName(),
                    uploadPath));
            // ... 其他属性设置保持不变 ...
            result.setPicWidth(width);
            result.setPicHeight(height);
            result.setPicScale(scale);
            result.setPicFormat(FileUtil.getSuffix(file.getName()));
            return result;
        } catch (Exception e) {
            log.error("文件上传失败", e); // 优化日志描述
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "文件上传失败");
        } finally {
            deleteTempFile(file);
        }
    }

    /**
     * 删除临时文件
     *
     * @param file 临时文件
     */
    private void deleteTempFile(File file) {
        if (file == null) {
            return;
        }
        boolean deleted = file.delete();
        if (!deleted) {
            log.error("delete file fail");
        }
    }

    /**
     * 校验图片
     *
     * @param multipartFile 上传的图片
     */
    private void validPicture(MultipartFile multipartFile) {
        if (ObjUtil.isEmpty(multipartFile)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件不能为空");
        }
        // 1. 获取图片大小
        long fileSize = multipartFile.getSize();
        // 2. 文件大小限制(根据自己需求限制大小)
        final long MAX_SIZE = 1024 * 1024 * 3;
        if (fileSize > MAX_SIZE) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件大小不能超过3MB");
        }
        // 2. 校验文件后缀
        String originalFilename = multipartFile.getOriginalFilename();
        String fileSuffix = FileUtil.getSuffix(originalFilename);
        final Set<String> ALLOWED_SUFFIX = Set.of("jpg", "jpeg", "png", "webp");
        if (fileSuffix != null && !ALLOWED_SUFFIX.contains(fileSuffix.toLowerCase())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件格式错误");
        }
    }
}